import { defineStore } from 'pinia'
import { ref, type Ref } from 'vue'
import { useUserStore } from '@/stores/user'
import { handleWsMessage } from '@/utils/basic'

export const useWebsocketStore = defineStore('websocket', () => {
  // state
  const msg = ref('') // 发送的消息
  const notifyMsg = ref({
    kind: '',
    name: '',
    status: ''
  }) // 通知消息
  const isReconnect = ref(true) // 是否重连
  const timeKey = ref(new Date().valueOf())
  const connetStatus: Ref<'已连接' | '初始化' | '连接失败' | '连接中' | '连接已断开' | '断开中'> =
    ref('初始化')
  // action
  const socket: Ref<null | WebSocket> = ref(null)
  let wsUrl = '' // 缓存ip
  // 连接成功
  const onopenWS = () => {
    isReconnect.value = true
    // console.log('webcoket 连接成功')
    connetStatus.value = '已连接'
    reconnrctCount.value = 0
    handleSendPing(5 * 1000) // 5秒发送心跳
    // 通知类自动刷新
    if (wsUrl.includes('/notify')) {
      pageRefresh()
    }
  }

  // 页面定期刷新
  let pageRefreshInterval: number | undefined = undefined
  const pageRefresh = (time = 3 * 60 * 1000) => {
    pageRefreshInterval && clearInterval(pageRefreshInterval)
    pageRefreshInterval = setInterval(() => {
      notifyMsg.value.kind = 'All'
      notifyMsg.value.name = ''
      notifyMsg.value.status = ''
      timeKey.value = new Date().valueOf()
      // 每三分钟重置重连
      if (isReconnect.value && reconnrctCount.value === 4) {
        reconnrctCount.value = 0
        initSocket(wsUrl, true)
      }
    }, time)
  }

  // 连接失败
  let setTimeoutPing: number | undefined = undefined
  const onerrorWS = (err: any) => {
    console.log('连接失败', err)
    connetStatus.value = '连接失败'
  }

  // WS数据接收
  const onmessageWS = (e: any) => {
    const jsonData: any = handleWsMessage(e.data || '{}')
    if (jsonData?.type) {
      if (wsUrl.includes('/notify')) {
        const notifyData = JSON.parse(jsonData.data || '{}')
        // 通知类处理
        notifyMsg.value.kind = notifyData.kind || ''
        notifyMsg.value.name = notifyData.name || ''
        notifyMsg.value.status = notifyData.status || ''
        timeKey.value = new Date().valueOf()
      } else {
        msg.value = jsonData.data
        timeKey.value = new Date().valueOf()
      }
    }
  }

  // 发送数据
  const sendWSMessage = (message: any) => {
    if (socket.value?.readyState === 1) {
      socket.value.send(JSON.stringify(message))
    }
  }

  // 断开连接
  const closeWS = () => {
    isReconnect.value = false
    socket.value?.send(
      JSON.stringify({
        type: 11,
        data: ''
      })
    )
    connetStatus.value = '断开中'
  }

  // 断开连接回调, 如果不是手动断开，进行五次重连回调
  let reconnectTimeout: number | undefined = undefined
  const reconnrctCount = ref(0)
  const oncloseWS = () => {
    setTimeoutPing && clearTimeout(setTimeoutPing)
    socket.value = null
    // 在线并且未手动关闭，就不退出
    if (window.navigator.onLine && isReconnect.value) {
      reconnectTimeout && clearTimeout(reconnectTimeout)
      if (reconnrctCount.value < 4) {
        reconnectTimeout = setTimeout(() => {
          reconnrctCount.value++
          initSocket(wsUrl, true)
        }, 1000)
      }
    } else {
      pageRefreshInterval && clearInterval(pageRefreshInterval)
      connetStatus.value = '连接已断开'
    }
  }

  // 手动增加数据
  const manualWSMessage = (data: string) => {
    timeKey.value = new Date().valueOf()
    msg.value = data
  }

  // 发送心跳
  const handleSendPing = (time = 5000) => {
    setTimeoutPing && clearTimeout(setTimeoutPing)
    sendPing()
    intervalExecutor(time, sendPing)
  }

  function intervalExecutor(interval: number, fn: Function) {
    const exec = () => {
      fn() // 执行函数
      setTimeoutPing && clearTimeout(setTimeoutPing)
      setTimeoutPing = setTimeout(exec, interval) // 设置下一次执行
    }
    setTimeout(exec, interval) // 首次执行并设置下一次执行
  }

  const sendPing = (ping = JSON.stringify({ type: 12, data: 'ping' })) => {
    if (socket.value && socket.value.readyState !== 2) {
      socket.value?.send(ping)
    }
  }

  // 初始化websocket
  const initSocket = (url: any, reconnetct = false) => {
    if (!socket.value) {
      if (!reconnetct) {
        connetStatus.value = '连接中'
      }
      const token = useUserStore().token
      wsUrl = `${url}`
      socket.value = new WebSocket(wsUrl, token)
      // 连接成功
      socket.value.onopen = onopenWS
      // 接收消息
      socket.value.onmessage = onmessageWS
      // 连接失败重连
      socket.value.onerror = onerrorWS
      // 断开连接
      socket.value.onclose = oncloseWS
    } else {
      // console.log('websocket已连接')
      isReconnect.value = true
    }
  }

  return {
    timeKey,
    msg,
    notifyMsg,
    connetStatus,
    manualWSMessage,
    initSocket,
    closeWS,
    sendWSMessage
  }
})
